﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using log4net.Core;
using SKBKontur.Logging.Model;
using SKBKontur.Serialization.Binding;

namespace SKBKontur.Cassandra.Logging.Model
{
    [DataContract]
    public class log4netEvent: LogEvent
    {
        [DataMember]
        private Dictionary<String, String> Parameters = new Dictionary<string, string>();

        [DataMember]
        [Utf8StringBinder]
        public string AppenderName { get; set; }

        public log4netEvent()
        {
        }

        public log4netEvent(LoggingEvent loggingEvent): this(loggingEvent, null, true)
        {
        }

        public log4netEvent(LoggingEvent loggingEvent, string appenderName, bool includeLocationInfo)
            : base(loggingEvent.ExceptionObject)
        {
            AppenderName = appenderName;
            EventLevel = Transform(loggingEvent.Level);
            LoggerName = loggingEvent.LoggerName;
            Message = loggingEvent.MessageObject.ToString();
            ThreadName = loggingEvent.ThreadName;
            TimeStamp = loggingEvent.TimeStamp;
            UserName = loggingEvent.UserName;

            if (includeLocationInfo)
            {
                ClassName = loggingEvent.LocationInformation.ClassName;
                FileName = loggingEvent.LocationInformation.FileName;
                LineNumber = loggingEvent.LocationInformation.LineNumber;
                MethodName = loggingEvent.LocationInformation.MethodName;
            }

            // todo Придумать фильтр, конфигурируемый на уровне Appender и умеющий:
            // - отключать использование параметров;
            // - фильтровать параметры по списку;
            // ? фильтровать параметры по регулярному выражению.
            var properties = loggingEvent.GetProperties();
            foreach (string name in properties.GetKeys())
                Parameters[name] = properties[name].ToString();
        }

        [DataMember]
        [Utf8StringBinder]
        public string LineNumber { get; set; }

        [DataMember]
        [Utf8StringBinder]
        public string ClassName { get; set; }

        [DataMember]
        [Utf8StringBinder]
        public string FileName { get; set; }

        [DataMember]
        [Utf8StringBinder]
        public string MethodName { get; set; }

        [DataMember]
        [Utf8StringBinder]
        public string LoggerName { get; set; }

        [Utf8StringDictionaryBinder("ParametersIndexer")]
        public string this[string name]
        {
            get { return Parameters[name]; }
            set { Parameters[name] = value; }
        }

        [DataMember]
        [Utf8StringBinder]
        public string UserName { get; set; }

        [DataMember]
        [Utf8StringBinder]
        public string ThreadName { get; set; }

        private static LogEventLevel Transform(Level level)
        {
            if (level.ToString().Equals(Level.Info.ToString()))
                return LogEventLevel.Info;
            if (level.ToString().Equals(Level.Warn.ToString()))
                return LogEventLevel.Warn;
            if (level.ToString().Equals(Level.Error.ToString()))
                return LogEventLevel.Error;
            if (level.ToString().Equals(Level.Fatal.ToString()))
                return LogEventLevel.Fatal;
            if (level.ToString().Equals(Level.Debug.ToString()))
                return LogEventLevel.Debug;
            return LogEventLevel.Unknown;
        }

        public IEnumerable<string> ParametersIndexer {get { return Parameters.Keys; }}
    }
}